package com.exsun.gateway.jt809.handler;

import com.exsun.gateway.jt809.common.DevInfoService;
import com.exsun.gateway.jt809.common.LinkMgr;
import com.exsun.gateway.jt809.common.LinkType;
import com.exsun.gateway.jt809.config.Jt809Config;
import com.exsun.gateway.jt809.data.PackageData;
import com.exsun.gateway.jt809.handler.cache.AuthorizeCode;
import com.exsun.gateway.jt809.handler.cache.MediaHandle;
import com.exsun.gateway.jt809.codec.protocol.Jt809Decode;
import com.exsun.gateway.jt809.codec.protocol.Jt809Encode;
import com.exsun.gateway.jt809.handler.cache.MediaListHandle;
import com.exsun.gateway.jt809.handler.cache.MediaPlayBackHandle;
import exsun.jt808.data.base.StatusResult;
import exsun.jt808.data.config.jt808.Jt808DistributeMsgTopic;
import exsun.jt808.data.config.jt808.Jt808MsgIdConfig;
import exsun.jt808.data.config.jt809.Jt809MsgIdConfig;
import exsun.jt808.data.config.jt809.VehicleExgMsgConstants;
import exsun.jt808.data.distribute_data.jt1078.*;
import exsun.jt808.data.distribute_data.jt808.*;
import exsun.jt808.data.enume.OrderSendStatus;
import exsun.jt808.data.jt809_data.BasicVehicleInfo;
import exsun.jt808.data.jt809_data.SendBaseEntity;
import exsun.jt808.data.jt809_data.alarm.main.UpWarnMsgUrgeTodoAck;
import exsun.jt808.data.jt809_data.video.main.UpAlarmMediaList;
import exsun.jt808.data.jt809_data.alarm.slave.DownWarnMsgExgInform;
import exsun.jt808.data.jt809_data.alarm.slave.DownWarnMsgFileListReq;
import exsun.jt808.data.jt809_data.alarm.slave.DownWarnMsgInformTips;
import exsun.jt808.data.jt809_data.alarm.slave.DownWarnMsgUrgeTodoReq;
import exsun.jt808.data.jt809_data.linkmanage.DownConnectRsp;
import exsun.jt808.data.jt809_data.linkmanage.UpConnectRsp;
import exsun.jt808.data.jt809_data.monitor.main.*;
import exsun.jt808.data.jt809_data.monitor.slave.*;
import exsun.jt808.data.jt809_data.platform.main.PlatformExgMsg;
import exsun.jt808.data.jt809_data.platform.main.UpPlatformMsgInfoAck;
import exsun.jt808.data.jt809_data.platform.main.UpPlatformMsgPostQueryAck;
import exsun.jt808.data.jt809_data.platform.slave.DownPlatformMsgInfoReq;
import exsun.jt808.data.jt809_data.platform.slave.DownPlatformMsgPostQueryReq;
import exsun.jt808.data.jt809_data.statistics.DownTotalRecvBackMsg;
import exsun.jt808.data.jt809_data.vehicledynamic.main.UpExgMsgReportDriverInfoAck;
import exsun.jt808.data.jt809_data.vehicledynamic.main.UpExgMsgReturnEndAck;
import exsun.jt808.data.jt809_data.vehicledynamic.main.UpExgMsgReturnStartupAck;
import exsun.jt808.data.jt809_data.vehicledynamic.main.UpExgMsgTakeEwaybillAck;
import exsun.jt808.data.jt809_data.vehicledynamic.slave.*;
import exsun.jt808.data.jt809_data.video.main.UpPlayBackMsgControlAck;
import exsun.jt808.data.jt809_data.video.main.UpPlayBackMsgStartupAck;
import exsun.jt808.data.jt809_data.video.main.UpRealVideoMsgEndAck;
import exsun.jt808.data.jt809_data.video.main.UpRealVideoMsgStartupAck;
import exsun.jt808.data.jt809_data.video.slave.*;
import exsun.jt808.data.upload_data.jt808.DriverInfo;
import exsun.jt808.data.util.GsonUtils;
import exsun.jt808.data.util.HttpUtil;
import exsun.jt808.data.util.Result;
import exsun.jt808.data.util.parse.BitOperator;
import exsun.jt808.data.util.parse.DecoderUtils;
import exsun.jt808.data.util.parse.HexStrUtil;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.text.DateFormat;
import java.util.*;

/**
 * @Author: 何蓉
 * @Date: 2019/3/25 10:30
 * @Description: 下级平台发往上级平台的应答
 */
@Service
public class ResponseHandler {

    private final static Logger log = LoggerFactory.getLogger(ResponseHandler.class);

    @Autowired
    Jt809Decode jt809Decode;

    @Autowired
    Jt809Encode jt809Encode;

    @Autowired
    DevInfoService devInfoService;

    @Autowired
    Jt809Config jt809Config;

    private DateFormat dateFormat = DateFormat.getDateTimeInstance();
    //调用接口超时时间
    private static final int TIMEOUT = 3000;

    /**
     * 上级平台的消息解析，并给我响应
     *
     * @param pkg
     * @return
     */
    public PackageData response(PackageData pkg) {
        PackageData pak = null;
        byte[] msgBodyBytes = pkg.getMsgBodyBytes();
        switch (pkg.getMsgHeader().getMsgId()) {
            // 主链路登录应答 无需应答
            case Jt809MsgIdConfig.UP_CONNECT_RSP:
                pak = upConnectRspAck(msgBodyBytes);
                break;
            // 主链路注销应答 无需应答
            case Jt809MsgIdConfig.UP_DISCONNECT_RSP:
                pak = upDisConnectRspAck(msgBodyBytes);
                break;
            // 主链路链接保持应答 无需应答
            case Jt809MsgIdConfig.UP_LINKTEST_RSP:
                pak = upLinkTestRspAck(msgBodyBytes);
                break;
            // 从链路登录请求
            case Jt809MsgIdConfig.DOWN_CONNECT_REQ:
                pak = downConnectReqAck(msgBodyBytes);
                break;
            // 从链路注销请求
            case Jt809MsgIdConfig.DOWN_DISCONNECT_REQ:
                pak = downDisConnectReqAck(msgBodyBytes);
                break;
            // 从链路链接保持请求
            case Jt809MsgIdConfig.DOWN_LINKTEST_REQ:
                pak = downLinkTestReqAck(msgBodyBytes);
                break;
            // 从链路断开通知 无需应答实时音视频请求指令下发
            case Jt809MsgIdConfig.DOWN_DISCONNECT_INFORM:
                pak = downDisConnectInformAck(msgBodyBytes);
                break;
            // 上级平台主动关闭链路通知消息 无需应答
            case Jt809MsgIdConfig.DOWN_CLOSELINK_INFORM:
                pak = downCloseLinkInformAck(msgBodyBytes);
                break;
            // 接收定位信息数量通知消息 无需应答
            case Jt809MsgIdConfig.DOWN_TOTAL_RECV_BACK_MSG:
                pak = downTotalRecvBackMsgAck(msgBodyBytes);
                break;

            // 车辆动态信息交换
            case Jt809MsgIdConfig.DOWN_EXG_MSG:
                int downExgMsgSubMsgId = DecoderUtils.parseIntFromBytes(msgBodyBytes, 22, 2);
                switch (downExgMsgSubMsgId) {
                    // 交换车辆定位信息消息 无需应答
                    case Jt809MsgIdConfig.DOWN_EXG_MSG_CAR_LOCATION:
                        pak = downExgMsgCarLocationAck(msgBodyBytes);
                        break;
                    // 车辆定位信息交换补发消息 无需应答
                    case Jt809MsgIdConfig.DOWN_EXG_MSG_HISTORY_ARCOSSAREA:
                        pak = downExgMsgHistroyArcossareaAck(msgBodyBytes);
                        break;
                    // 车辆静态消息交换 无需应答
                    case Jt809MsgIdConfig.DOWN_EXG_MSG_CAR_INFO:
                        pak = downExgMsgCarInfoAck(msgBodyBytes);
                        break;
                    //启动车辆定位信息交换请求
                    case Jt809MsgIdConfig.DOWN_EXG_MSG_RETURN_STARTUP:
                        pak = downExgMsgReturnStartupAck(msgBodyBytes);
                        break;
                    // 取消车辆定位信息交换请求
                    case Jt809MsgIdConfig.DOWN_EXG_MSG_RETURN_END:
                        pak = downExgMsgReturnEndAck(msgBodyBytes);
                        break;
                    // 申请交换指定车辆定位信息应答 无需应答
                    case Jt809MsgIdConfig.DOWN_EXG_MSG_APPLY_FOR_MONITOR_STARTUP_ACK:
                        pak = downExgMsgApplyForMonitorStartupAck(msgBodyBytes);
                        break;
                    // 取消交换指定车辆定位信息应答 无需应答
                    case Jt809MsgIdConfig.DOWN_EXG_MSG_APPLY_FOR_MONITOR_END_ACK:
                        pak = downExgMsgApplyForMonitorEndAck(msgBodyBytes);
                        break;
                    // 补发车辆定位信息应答 无需应答
                    case Jt809MsgIdConfig.DOWN_EXG_MSG_APPLY_HISGNSSDATA_ACK:
                        pak = downExgMsgApplyHisGnssDataAck(msgBodyBytes);
                        break;
                    // 上报驾驶员身份识别信息请求
                    case Jt809MsgIdConfig.DOWN_EXG_MSG_REPORT_DRIVER_INFO:
                        pak = downExgMsgReportDriverInfoAck(msgBodyBytes);
                        break;
                    // 上报车辆电子运单请求
                    case Jt809MsgIdConfig.DOWN_EXG_MSG_TAKE_EWAYBIL_REQ:
                        pak = downExgMsgTakeEwaybillAck(msgBodyBytes);
                        break;
                    default:
                        break;
                }
                break;

            // 车辆静态信息交换
            case Jt809MsgIdConfig.DOWN_BASE_MSG:
                int downBaseMsgSubMsgId = DecoderUtils.parseIntFromBytes(msgBodyBytes, 22, 2);
                switch (downBaseMsgSubMsgId) {
                    case Jt809MsgIdConfig.DOWN_BASE_MSG_VEHICLE_ADDED:
                        //downBaseMsgVehicleAdded(pkg.getMsgBodyBytes());
                        break;
                    default:
                        break;
                }
                break;

            // 平台间交换
            case Jt809MsgIdConfig.DOWN_PLATFORM_MSG:
                int downPlatformMsgSubMsgId = DecoderUtils.parseIntFromBytes(msgBodyBytes, 22, 2);
                switch (downPlatformMsgSubMsgId) {
                    // 平台查岗请求
                    case Jt809MsgIdConfig.DOWN_PLATFORM_MSG_POST_QUERY_REQ:
                        pak = downPlatformMsgPostQueryAck(msgBodyBytes);
                        break;
                    // 下发平台间报文请求
                    case Jt809MsgIdConfig.DOWN_PLATFORM_MSG_INFO_REQ:
                        pak = downPlatformMsgInfoAck(msgBodyBytes);
                        break;
                    default:
                        break;
                }
                break;

            // 车辆报警
            case Jt809MsgIdConfig.DOWN_WARN_MSG:
                int downWarnMsgSubMsgId = DecoderUtils.parseIntFromBytes(msgBodyBytes, 22, 2);
                switch (downWarnMsgSubMsgId) {
                    // 报警督办请求
                    case Jt809MsgIdConfig.DOWN_WARN_MSG_URGE_TODO_REQ:
                        pak = downWarnMsgUrgeTodoReqAck(msgBodyBytes);
                        break;
                    // 报警预警消息 无需应答
                    case Jt809MsgIdConfig.DOWN_WARN_MSG_URGE_INFORM_TIPS:
                        pak = downWarnMsgInformTipsAck(msgBodyBytes);
                        break;
                    // 实时报警信息交换
                    case Jt809MsgIdConfig.DOWN_WARN_MSG_URGE_EXG_INFORM:
                        pak = downWarnMsgExgInformAck(pkg.getMsgBodyBytes());
                        break;
                    //报警附件目录请求消息
                    case Jt809MsgIdConfig.DOWN_WARN_MSG_FILELIST_REQ:
                        pak = downWarnMsgFileListReq(msgBodyBytes);
                        break;
                    default:
                        break;
                }
                break;

            // 车辆监控
            case Jt809MsgIdConfig.DOWN_CTRL_MSG:
                int downCtrlMsgSubMsgId = DecoderUtils.parseIntFromBytes(msgBodyBytes, 22, 2);
                switch (downCtrlMsgSubMsgId) {
                    // 车辆单向监听请求
                    case Jt809MsgIdConfig.DOWN_CTRL_MSG_MONITOR_VEHICLE_REQ:
                        pak = downCtrlMsgMonitorVehicleReqAck(msgBodyBytes);
                        break;
                    // 车辆拍照请求
                    case Jt809MsgIdConfig.DOWN_CTRL_MSG_TAKE_PHOTO_REQ:
                        pak = downCtrlMsgTakePhotoReqAck(msgBodyBytes);
                        break;
                    // 下发车辆报文请求
                    case Jt809MsgIdConfig.DOWN_CTRL_MSG_TEXT_INFO:
                        pak = downCtrlMsgTextInfoAck(msgBodyBytes);
                        break;
                    // 上报车辆行驶记录请求
                    case Jt809MsgIdConfig.DOWN_CTRL_MSG_TAKE_TRAVEL_REQ:
                        pak = downCtrlMsgTakeTravelReqAck(msgBodyBytes);
                        break;
                    // 车辆应急接入监管平台请求消息
                    case Jt809MsgIdConfig.DOWN_CTRL_MSG_EMERGENCY_MONITORING_REQ:
                        pak = downCtrlMsgEmergencyMonitoringReqAck(msgBodyBytes);
                        break;
                    default:
                        break;
                }
                break;
            case Jt809MsgIdConfig.DOWN_PLAYBACK_MSG:
                int downPlayBackMsgSubMsgId = DecoderUtils.parseIntFromBytes(msgBodyBytes, 22, 2);
                switch (downPlayBackMsgSubMsgId) {
                    // 远程录像回放控制消息
                    case Jt809MsgIdConfig.DOWN_PLAYBACK_MSG_CONTROL:
                        pak = downPlayBackMsgControl(msgBodyBytes);
                        break;
                    // 远程录像回放请求消息
                    case Jt809MsgIdConfig.DOWN_PLAYBACK_MSG_STARTUP:
                        pak = downPlayBackMsgStartup(msgBodyBytes);
                        break;
                }
                break;
            case Jt809MsgIdConfig.DOWN_REALVIDEO_MSG:
                int downRealVideoMsgSubMsgId = DecoderUtils.parseIntFromBytes(msgBodyBytes, 22, 2);
                switch (downRealVideoMsgSubMsgId) {
                    // 主动请求停止实时音视频传输消息
                    case Jt809MsgIdConfig.DOWN_REALVIDEO_MSG_END:
                        pak = downRealVideoMsgEnd(msgBodyBytes);
                        break;
                    // 实时音视频请求消息
                    case Jt809MsgIdConfig.DOWN_REALVIDEO_MSG_STARTUP:
                        pak = downRealVideoMsgStartup(msgBodyBytes);
                        break;
                }
                break;
            case Jt809MsgIdConfig.DOWN_SEARCH_MSG:
                int downSearchMsgSubMsgId = DecoderUtils.parseIntFromBytes(msgBodyBytes, 22, 2);
                switch (downSearchMsgSubMsgId) {
                    // 主动上传音视频资源目录信息应答消息
                    case Jt809MsgIdConfig.DOWN_FILELIST_MSG_ACK:
                        pak = downFileListMsgAck(msgBodyBytes);
                        break;
                    // 查询音视频资源目录请求消息
                    case Jt809MsgIdConfig.DOWN_REALVIDEO_FILELIST_REQ:
                        pak = downRealVideoFileListReq(msgBodyBytes);
                        break;
                }
                break;

            default:
                break;
        }
        return pak;
    }

    /**
     * 链路管理----------------start
     */

    /**
     * 主链路登录应答的下级平台应答
     *
     * @param body
     * @return 无需应答
     */
    public PackageData upConnectRspAck(byte[] body) {
        UpConnectRsp data = jt809Decode.upConnectRsp(body);
        jt809Decode.verifyCode = data.getCheckCode();
        log.info("主链路登录应答，" + (data.getResult() == 0 ? "成功" : "失败，应答码：" + data.getResult()));
        if(data.getResult() == 0) {
            LinkMgr.setMasterChannelLoggingStatus(true);
        }
        return null;
    }

    /**
     * 主链路注销应答的下级平台应答
     * todo 此处暂时只记录（持久到数据库？）不中断主从链路
     *
     * @param body
     * @return 无需应答
     */
    public PackageData upDisConnectRspAck(byte[] body) {
        jt809Decode.upDisConnectRsp(body);
        log.info("主链路注销应答!!");
        return null;
    }

    /**
     * 主链路连接保持应答的下级平台应答
     *
     * @param body
     * @return 无需应答
     */
    public PackageData upLinkTestRspAck(byte[] body) {
        jt809Decode.upLinkTestRsp(body);
        return null;
    }

    /**
     * 从链路登录请求消息应答
     *
     * @return
     */
    public PackageData downConnectReqAck(byte[] body) {
        int data = jt809Decode.downConnectReq(body);
        int ret = 1;
        if (data == jt809Decode.verifyCode) {
            ret = 0;
        }
        DownConnectRsp rsp = new DownConnectRsp();
        rsp.setResult(ret);
        return new PackageData(Jt809MsgIdConfig.DOWN_CONNECT_RSP, jt809Encode.downConnectRsp(rsp), LinkType.SLAVE);
    }

    /**
     * 从链路注销请求消息应答
     * todo 此处暂时不中断从链路，和记录注销日志。只打印日志
     *
     * @param body
     * @return 应答数据体为空
     */
    public PackageData downDisConnectReqAck(byte[] body) {
        int verifyCode = jt809Decode.downDisConnectReq(body);
        log.info("从链路注销请求消息!!，校验码：{}", verifyCode);
        return new PackageData(Jt809MsgIdConfig.DOWN_DISCONNECT_RSP, new byte[0], LinkType.SLAVE);
    }

    /**
     * 从链路连接保持请求应答
     *
     * @param body
     * @return 应答数据体为空
     */
    public PackageData downLinkTestReqAck(byte[] body) {
        jt809Decode.downLinkTestReq(body);
        return new PackageData(Jt809MsgIdConfig.DOWN_LINKTEST_RSP, new byte[0], LinkType.SLAVE);
    }

    /**
     * 从链路断开通知消息应答
     *
     * @param body
     * @return 无需应答
     */
    public PackageData downDisConnectInformAck(byte[] body) {
        int reasonCode = jt809Decode.downDisConnectInfo(body);
        String reason;
        if (reasonCode == 0) {
            reason = "无法连接下级平台指定的服务ip与端口";
        } else if (reasonCode == 1) {
            reason = "上级平台客户端与下级平台服务端断开";
        } else {
            reason = "其他原因";
        }
        log.info("从链路断开通知消息，原因码：{}，原因：{}", reasonCode, reason);
        return null;
    }

    /**
     * 上级平台主动关闭链路通知消息应答
     *
     * @param body
     * @return 无需应答
     */
    public PackageData downCloseLinkInformAck(byte[] body) {
        int reasonCode = jt809Decode.downCloseLinkInfrom(body);
        log.info("上级平台主动关闭链路通知消息，原因码：{}，原因：{}", reasonCode,
                reasonCode == 0 ? "网关重启" : "其他原因");
        return null;
    }

    /**
     * 链路管理----------------start
     */


    /**
     * 接收定位信息数量通知消息
     * 上级平台定量通知下级平台上传的车辆定位信息数量
     *
     * @param body
     * @return 无需应答
     */
    public PackageData downTotalRecvBackMsgAck(byte[] body) {
        DownTotalRecvBackMsg downTotalRecvBackMsg = jt809Decode.downTotalRecvBackMsg(body);
        int dynamicInfoTotal = downTotalRecvBackMsg.getDynamicInfoTotal();
        Date startTime = downTotalRecvBackMsg.getStartTime();
        Date endTime = downTotalRecvBackMsg.getEndTime();

        log.info("从{}至{}下级平台共上传{}条车辆定位信息！！！", dateFormat.format(startTime),
                dateFormat.format(endTime), dynamicInfoTotal);
        return null;
    }

    /**
     * 车辆监管----------------start
     */

    /**
     * 车辆单向监听请求应答
     *
     * @param body
     * @return
     */
    public PackageData downCtrlMsgMonitorVehicleReqAck(byte[] body) {
        //1、解析
        DownCtrlMsgMonitorVehicleReq entity = jt809Decode.downCtrlMsgMonitorVehicleReq(body);
        String clientId = getDevNoByVehNo(entity.getBasicVehicleInfo());
        CallBack send = new CallBack(1, entity.getMonitorTel());
        send.setDistributeMsgTopic(Jt808DistributeMsgTopic.CallBack_Send);
        send.devNo = clientId;
        send.response = true;
        StatusResult clientRsp = HttpRequest.postOrder(jt809Config.getHttpRequestUrl(), send, TIMEOUT);

        UpCtrlMsgMonitorVehicleAck rspTo809 = new UpCtrlMsgMonitorVehicleAck();
        rspTo809.setBasicVehicleInfo(entity.getBasicVehicleInfo());
        rspTo809.setResult((clientRsp != null &&clientRsp.StatusEqual(OrderSendStatus.设备通用应答成功)) ? 0 : 1);
        return new PackageData(Jt809MsgIdConfig.UP_CTRL_MSG_MONITOR_VEHICLE_ACK, jt809Encode.upCtrlMsgMonitorVehicleAck(rspTo809)
                , LinkType.MASTER);
    }

    /**
     * 车辆拍照请求应答
     *
     * @param body
     * @return
     */
    public PackageData downCtrlMsgTakePhotoReqAck(byte[] body) {
        //1、解析
        DownCtrlMsgTakePhotoReq entity = jt809Decode.downCtrlMsgTakePhotoReq(body);
        //2、下发
        String devNo = getDevNoByVehNo(entity.getBasicVehicleInfo());
        TakePhotoRightAway send = new TakePhotoRightAway();
        send.setChannelId(entity.getLensId());
        send.setCmd(1); // 拍一张
        send.setResolutionRatio(entity.getSize());
        send.devNo = devNo;
        send.response = false;
        send.requestId = "3412568";
        send.msgId = (int)Long.parseLong("8801",16);
        send.serialNo = 123456;
        send.userId = "123456";
        send.userName = "wupeng";
        send.distributeTime = new Date();
        send.distributeMsgTopic = Jt808DistributeMsgTopic.TakePhotoRightAway_Send;
        log.info("输出拍照对象参数值:{}", send.toString());

        //默认为成功，减少图片匹配失败的情况
        //结果处理
        int photoResFlag = 2;
//        int photoResFlag = getResult(pushClientResp, devNo, entity);
        UpCtrlMsgTakePhotoAck upCtrlMsgTakePhotoAck = new UpCtrlMsgTakePhotoAck();
        upCtrlMsgTakePhotoAck.setBasicVehicleInfo(entity.getBasicVehicleInfo());
        upCtrlMsgTakePhotoAck.setPhotoRspFlag(photoResFlag);
        upCtrlMsgTakePhotoAck.setGnssData(null);
        upCtrlMsgTakePhotoAck.setLensId(entity.getLensId());
        upCtrlMsgTakePhotoAck.setSizeType(entity.getSize());
        upCtrlMsgTakePhotoAck.setType(1);
        upCtrlMsgTakePhotoAck.setPhoto(new byte[0]);

        MediaHandle.inst.add(devNo, entity);
        log.info("缓存拍照请求:devNo:{},LensId:{}", devNo,entity.getLensId());


        StatusResult clientRsp = HttpRequest.postOrder(jt809Config.getHttpRequestUrl(), send, TIMEOUT);

        log.info("拍照调用完成！");

        return new PackageData(Jt809MsgIdConfig.UP_CTRL_MSG_TAKE_PHOTO_ACK,
                jt809Encode.upCtrlMsgTakePhotoAck(upCtrlMsgTakePhotoAck), LinkType.MASTER);
    }

    /**
     * 下发车辆报文请求
     *
     * @param body
     * @return
     */
    public PackageData downCtrlMsgTextInfoAck(byte[] body) {
        //1、解析
        DownCtrlMsgTextInfo entity = jt809Decode.downCtrlMsgTextInfo(body);
        //2、下发
        String devNo = getDevNoByVehNo(entity.getBasicVehicleInfo());

        String content = entity.getMsgContent();
        boolean urgency = entity.getMsgPriority()== 0 ? true : false;
        boolean terminalDisplay = false;
        boolean ttsPlay = false;
        boolean screenDisplay =false;
        int msgType =0;

        //武汉市运管语音播报扩展
        String[] splits = content.split(";");
        for (String split : splits) {
            String[] values = split.split(":=");
            if(values.length != 2)continue;
            if(values[0].equals("FLAG"))
            {
                int nFlag = Integer.parseInt(values[1]);
                String bin = HexStrUtil.byteArrToBinStr(new byte[]{(byte) nFlag}, 0, 1);
                urgency = bin.charAt(7) == '1';
                terminalDisplay = bin.charAt(5) == '1';
                ttsPlay=bin.charAt(4) == '1';
                screenDisplay=bin.charAt(3) == '1';
            }
            if(values[0].equals("MSG"))
            {
                content = values[1];
            }
        }
        //武汉市运管语音播报扩展结束

        TextSend send = new TextSend();
        send.setUrgency(urgency);
        send.setTerminalDisplay(terminalDisplay);
        send.setTtsPlay(ttsPlay);
        send.setScreenDisplay(screenDisplay);
        send.setMsgType(msgType);
        send.setContent(content);
        send.setDevNo(devNo);
        send.response = true;
        send.setDistributeMsgTopic(Jt808DistributeMsgTopic.Text_Send);
        StatusResult clientRsp = HttpRequest.postOrder(jt809Config.getHttpRequestUrl(), send, TIMEOUT);
        //3、应答
        UpCtrlMsgTextInfoAck rspTo809 = new UpCtrlMsgTextInfoAck();
        rspTo809.setBasicVehicleInfo(entity.getBasicVehicleInfo());
        rspTo809.setMsgId(entity.getMsgSequence());
        rspTo809.setResult((clientRsp != null &&clientRsp.StatusEqual(OrderSendStatus.设备通用应答成功)) ? 0 : 1);
        return new PackageData(Jt809MsgIdConfig.UP_CTRL_MSG_TEXT_INFO_ACK, jt809Encode.upCtrlMsgTextInfoAck(rspTo809), LinkType.MASTER);
    }

    /**
     * 上报车辆行驶记录请求
     *
     * @param body
     * @return
     */
    public PackageData downCtrlMsgTakeTravelReqAck(byte[] body) {
        //1、解析
        DownCtrlMsgTakeTravelReq entity = jt809Decode.downCtrlMsgTakeTravelReq(body);
        //2、下发
        String clientId = getDevNoByVehNo(entity.getBasicVehicleInfo());
        CollectData send = new CollectData();
        send.setCmd(entity.getCmdType());
        send.setContent("");
        send.devNo = clientId;
        send.setDistributeMsgTopic(Jt808DistributeMsgTopic.CollectData_Send);
        send.response = true;
        StatusResult clientRsp = HttpRequest.postOrder(jt809Config.getHttpRequestUrl(), send, TIMEOUT);


        //3、应答
        UpCtrlMsgTakeTravelAck rspTo809 = new UpCtrlMsgTakeTravelAck();
        rspTo809.setBasicVehicleInfo(entity.getBasicVehicleInfo());
        //todo
        rspTo809.setTravelDataInfo((clientRsp != null &&clientRsp.StatusEqual(OrderSendStatus.设备通用应答成功)) ? "" : "");
        return new PackageData(Jt809MsgIdConfig.UP_CTRL_MSG_TEXT_INFO_ACK, jt809Encode.upCtrlMsgTakeTravelAck(rspTo809), LinkType.MASTER);
    }

    /**
     * 通过车牌号获得设备号
     *
     * @param basicVehicleInfo
     * @return
     */
    private String getDevNoByVehNo(BasicVehicleInfo basicVehicleInfo) {

        return devInfoService.getDevNoByVehNoByFile(basicVehicleInfo.getVehicleNo());
    }

    /**
     * 车辆应急接入监管平台请求消息应答
     *
     * @param body
     * @return
     */
    public PackageData downCtrlMsgEmergencyMonitoringReqAck(byte[] body) {
        //1、解析
        DownCtrlMsgEmergencyMonitoringReq entity = jt809Decode.downCtrlMsgEmergencyMonitoringReq(body);
        //2、下发
        String clientId = getDevNoByVehNo(entity.getBasicVehicleInfo());
        TerminalControl send = new TerminalControl();
        //连接控制;监管平台鉴权码;拨号点名称;拨号用户名;拨号密码;地址;TCP 端口;UDP 端口;连接到指定服务器时限（单位：min）
        String value = String.format("{};{};{};{};{};{};{};{};{}", 0, entity.getAuthenticationCode(), entity.getAccessPointName(),
                entity.getUserName(), entity.getPassWord(), entity.getServerIp(), entity.getTcpPort(), entity.getUdpPort(),
                (entity.getEndTime().getTime() - new Date().getTime()) / 60000);
        send.setCmd(2);
        send.setValue(value);
        send.devNo = clientId;
        send.response = true;
        send.setDistributeMsgTopic(Jt808DistributeMsgTopic.TerminalControl_Send);
        StatusResult clientRsp = HttpRequest.postOrder(jt809Config.getHttpRequestUrl(), send, TIMEOUT);
        UpCtrlMsgEmergencyMonitoringAck rspTo809 = new UpCtrlMsgEmergencyMonitoringAck();
        rspTo809.setBasicVehicleInfo(entity.getBasicVehicleInfo());
        rspTo809.setResult((clientRsp != null &&clientRsp.StatusEqual(OrderSendStatus.设备通用应答成功)) ? 0 : 1);
        return new PackageData(Jt809MsgIdConfig.UP_CTRL_MSG_EMERGENCY_MONITORING_ACK, jt809Encode.upCtrlEmergencyMonitoringAck(rspTo809)
                , LinkType.MASTER);
    }

    /**
     *  车辆监管----------------end
     */

    /**
     * 车辆报警-------------------start
     */

    /**
     * 车辆报警督办应答
     *
     * @return
     */
    private PackageData downWarnMsgUrgeTodoReqAck(byte[] msgBodyBytes) {
        DownWarnMsgUrgeTodoReq downWarnMsgUrgeTodoReq = jt809Decode.downWarnMsgUrgeTodoReq(msgBodyBytes);
        UpWarnMsgUrgeTodoAck upWarnMsgUrgeTodoAck = new UpWarnMsgUrgeTodoAck();
        upWarnMsgUrgeTodoAck.setSupervisionId(downWarnMsgUrgeTodoReq.getSupervisionId());
        upWarnMsgUrgeTodoAck.setBasicVehicleInfo(downWarnMsgUrgeTodoReq.getBasicVehicleInfo());
        // todo 此处的督办结果应该要查询数据库才能给出结果
        return null;
    }

    /**
     * 实时交换车辆报警信息消息的下级平台应答
     * 用于上级平台向【车辆跨域目的地下级平台】下发车辆当前的报警消息
     * todo 是否需要保存跨域车辆的报警信息？？？
     *
     * @param msgBodyBytes
     * @return 无需应答
     */
    private PackageData downWarnMsgExgInformAck(byte[] msgBodyBytes) {
        DownWarnMsgExgInform downWarnMsgExgInform = jt809Decode.downWarnMsgExgInform(msgBodyBytes);
        BasicVehicleInfo basicVehicleInfo = downWarnMsgExgInform.getBasicVehicleInfo();
        log.info("接受到上级平台的实时报警消息：车牌号为：{}，车辆颜色代码为：{}，报警描述：{}",
                basicVehicleInfo.getVehicleNo(), basicVehicleInfo.getVehicleColor(), downWarnMsgExgInform.getWarnContent());
        return null;
    }

    /**
     * 报警预警消息应答的下级平台应答
     * 用于上级平台向【车辆归属或车辆跨域下级平台】发送车辆相关报警预警或提示消息
     * todo 此处需要保存报警预警消息吗？？
     *
     * @param msgBodyBytes
     * @return 无需应答
     */
    private PackageData downWarnMsgInformTipsAck(byte[] msgBodyBytes) {
        DownWarnMsgInformTips downWarnMsgInformTips = jt809Decode.downWarnMsgInformTips(msgBodyBytes);
        BasicVehicleInfo basicVehicleInfo = downWarnMsgInformTips.getBasicVehicleInfo();
        log.info("接受到上级平台的报警预警消息：车牌号为：{}，车辆颜色代码为：{}，报警描述：{}",
                basicVehicleInfo.getVehicleNo(), basicVehicleInfo.getVehicleColor(), downWarnMsgInformTips.getWarnContent());
        return null;
    }

    /**
     * 报警附件目录请求消息
     */
    private PackageData downWarnMsgFileListReq(byte[] body){
        DownWarnMsgFileListReq entity = jt809Decode.downWarnMsgFileListReq(body);
        log.info("报警附件目录请求消息指令下发! 车牌号:{},报警Id:{}",entity.getBasicVehicleInfo().getVehicleNo(),entity.getInfo_id());
        return null;
    }

    /**
     * 车辆报警-------------------end
     */

    /**
     * 平台间交换--------start
     */

    /**
     * 下发平台间报文应答
     *
     * @param msgBodyBytes
     * @return
     */
    private PackageData downPlatformMsgInfoAck(byte[] msgBodyBytes) {
        DownPlatformMsgInfoReq downPlatformMsgInfoReq = jt809Decode.downPlatformMsgInfoReq(msgBodyBytes);
        UpPlatformMsgInfoAck upPlatformMsgInfoAck = new UpPlatformMsgInfoAck();
        upPlatformMsgInfoAck.setInfoId(downPlatformMsgInfoReq.getInfoId());
        return new PackageData(Jt809MsgIdConfig.UP_PLATFORM_MSG_INFO_ACK,
                jt809Encode.upPlatformMsgInfoAck(upPlatformMsgInfoAck), LinkType.MASTER);
    }

    /**
     * 平台查岗应答
     * todo 平台查岗暂时没有建表，没有给出实际的应答
     *
     * @param msgBodyBytes
     * @return
     */
    private PackageData downPlatformMsgPostQueryAck(byte[] msgBodyBytes) {
        DownPlatformMsgPostQueryReq downPlatformMsgPostQueryReq = jt809Decode.downPlatformMsgPostQueryReq(msgBodyBytes);
        UpPlatformMsgPostQueryAck upPlatformMsgPostQueryAck = new UpPlatformMsgPostQueryAck();
        int infoId = downPlatformMsgPostQueryReq.getInfoId();
        upPlatformMsgPostQueryAck.setInfoId(infoId);

        // todo 添加平台查岗记录
        PlatformExgMsg platformExgMsg = new PlatformExgMsg();
        platformExgMsg.setInformationId(infoId+"");
        platformExgMsg.setGmtCreate(new Date());
        platformExgMsg.setInformationDetail(downPlatformMsgPostQueryReq.getInfoContent());
        platformExgMsg.setPlatform("省运管");
        platformExgMsg.setStatus(1);
        platformExgMsg.setStatusName("未应答");
        try {
            HttpUtil.send(jt809Config.getHttpGetUrl()+"/save",GsonUtils.getJsonFromObject(platformExgMsg),"UTF-8");
        } catch (IOException e) {
            e.printStackTrace();
        }
        // todo 等下级平台监管人员回复后才回复上级平台
        return new PackageData(Jt809MsgIdConfig.UP_PLATFORM_MSG_POST_QUERY_ACK, new byte[0], LinkType.MASTER);
    }

    /**
     * 平台间交换--------end
     */


    /**
     * 车辆动态信息交换应答----start
     */

    /**
     * 交换车辆静态信息消息的下级平台应答
     * 首次启动跨越车辆定位信息交换
     * 或以后交换过程中车辆静态信息发生变化时
     * todo 下级平台自行更新车辆静态信息？？
     *
     * @param msgBodyBytes
     * @return 无需应答
     */
    private PackageData downExgMsgCarInfoAck(byte[] msgBodyBytes) {
        DownExgMsgCarInfo downExgMsgCarInfo = jt809Decode.downExgMsgCarInfo(msgBodyBytes);
        BasicVehicleInfo basicVehicleInfo = downExgMsgCarInfo.getBasicVehicleInfo();
        log.info("接收到来自上级平台的车辆静态消息，车牌号为{}，颜色代码为{}，静态消息内容为：{}",
                basicVehicleInfo.getVehicleNo(), basicVehicleInfo.getVehicleColor(), downExgMsgCarInfo.getContent());
        return null;
    }

    /**
     * 车辆定位信息交换补发消息的下级平台应答
     * todo 接受到上级平台补发信息作何处理？
     *
     * @param msgBodyBytes
     * @return 无需应答
     */
    private PackageData downExgMsgHistroyArcossareaAck(byte[] msgBodyBytes) {
        DownExgMsgHistoryArcossArea downExgMsgHistoryArcossArea = jt809Decode.downExgMsgHistoryArcossArea(msgBodyBytes);
        BasicVehicleInfo basicVehicleInfo = downExgMsgHistoryArcossArea.getBasicVehicleInfo();
        log.info("下级平台申请的车牌号为{}，颜色代码为{}的车辆由上级平台补发到我方平台",
                basicVehicleInfo.getVehicleNo(), basicVehicleInfo.getVehicleColor());
        return null;
    }

    /**
     * 交换车辆定位信息消息的下级平台应答
     * 上级平台通过此消息不间断的向下级平台
     * 下发车辆驶入该区域的定位信息
     * 直到车辆驶离该区域
     * todo 接收到车辆信息作何处理？？
     *
     * @param msgBodyBytes
     * @return 无需应答
     */
    private PackageData downExgMsgCarLocationAck(byte[] msgBodyBytes) {
        DownExgMsgCarInfo downExgMsgCarInfo = jt809Decode.downExgMsgCarInfo(msgBodyBytes);
        BasicVehicleInfo basicVehicleInfo = downExgMsgCarInfo.getBasicVehicleInfo();
        log.info("车牌号为{}，颜色代码为{}的车辆驶入我方所属区域",
                basicVehicleInfo.getVehicleNo(), basicVehicleInfo.getVehicleColor());
        return null;
    }


    /**
     * 上报车辆电子运单请求应答
     *
     * @param msgBodyBytes
     * @return
     */
    private PackageData downExgMsgTakeEwaybillAck(byte[] msgBodyBytes) {
        DownExgMsgTakeEwaybillReq downExgMsgTakeEwaybillReq = jt809Decode.downExgMsgTakeEwaybillReq(msgBodyBytes);
        UpExgMsgTakeEwaybillAck upExgMsgTakeEwaybillAck = new UpExgMsgTakeEwaybillAck();
        upExgMsgTakeEwaybillAck.setBasicVehicleInfo(downExgMsgTakeEwaybillReq.getBasicVehicleInfo());
//        String ewayBillContent = vehicleEwayBillMongoService.selectEwayBillByVehicleNo(
//                downExgMsgTakeEwaybillReq.getBasicVehicleInfo().getVehicleNo());
        //todo 查询电子运单
        String ewayBillContent ="";
                upExgMsgTakeEwaybillAck.setEwayBillContent(ewayBillContent);
        return new PackageData(Jt809MsgIdConfig.UP_EXG_MSG_TAKE_EWAYBILL_ACK,
                jt809Encode.upExgMsgTakeEwaybillAck(upExgMsgTakeEwaybillAck), LinkType.MASTER);
    }

    /**
     * 上报驾驶员身份识别信息请求应答
     *
     * @param msgBodyBytes
     * @return
     */
    private PackageData downExgMsgReportDriverInfoAck(byte[] msgBodyBytes) {
        DownExgMsgReportDriverInfo downExgMsgReturnStartup = jt809Decode.downExgMsgReportDriverInfo(msgBodyBytes);
        UpExgMsgReportDriverInfoAck upExgMsgReportDriverInfoAck = new UpExgMsgReportDriverInfoAck();
        upExgMsgReportDriverInfoAck.setBasicVehicleInfo(downExgMsgReturnStartup.getBasicVehicleInfo());

        //todo 查询base_driver_info查到身份证号
//        DriverInfo driverInfo = driverVehicleStatMongoService.selectDriverInfoByVehicleNo(
//                downExgMsgReturnStartup.getBasicVehicleInfo().getVehicleNo());
//        BaseDriverInfo baseDriverInfo = baseDriverInfoService.queryByQualificationCode(driverInfo.getQualificationCode());
//        String driverId = baseDriverInfo.getIcCard();
        DriverInfo driverInfo = new DriverInfo();
        String driverId = "";
        upExgMsgReportDriverInfoAck.setDriverId(driverId);

        upExgMsgReportDriverInfoAck.setDriverName(driverInfo.getDriverName());
        upExgMsgReportDriverInfoAck.setLicense(driverInfo.getQualificationCode());
        upExgMsgReportDriverInfoAck.setOrgName(driverInfo.getIssuingAuthority());
        return new PackageData(Jt809MsgIdConfig.UP_EXG_MSG_REPROT_DRIVER_INFO_ACK,
                jt809Encode.upExgMsgReportDriverInfoAck(upExgMsgReportDriverInfoAck), LinkType.MASTER);
    }

    /**
     * 补发车辆定位信息应答的下级平台应答
     * todo 下级平台是否需要记录补发应答结果
     *
     * @param mssBodyBytes
     * @return 无需应答
     */
    private PackageData downExgMsgApplyHisGnssDataAck(byte[] mssBodyBytes) {
        DownExgMsgApplyHisGnssDataAck downExgMsgApplyHisGnssDataAck = jt809Decode.downExgMsgApplyHisGnssDataAck(mssBodyBytes);
        int resultCode = downExgMsgApplyHisGnssDataAck.getResult();
        String result = VehicleExgMsgConstants.applyForHisGnssDataResult(resultCode);
        log.info("补发车辆定位信息应答结果：{}", result);
        return null;
    }

    /**
     * 取消交换指定车辆定位信息应答的下级平台应答
     * todo 下级平台是否需要记录取消结果？？
     *
     * @param msgBodyBytes
     * @return 无需应答
     */
    private PackageData downExgMsgApplyForMonitorEndAck(byte[] msgBodyBytes) {
        DownExgMsgApplyForMonitorEndAck downExgMsgApplyForMonitorEndAck
                = jt809Decode.downExgMsgApplyForMonitorEndAck(msgBodyBytes);
        int resultCode = downExgMsgApplyForMonitorEndAck.getResult();
        String result = VehicleExgMsgConstants.applyForMonitorEnd(resultCode);
        log.info("取消交换指定车辆定位信息结果：{}", result);

        // todo 取消交换指定车辆信息上级平台响应后，更新库中的申请记录
//        VehicleExgMsg vehicleExgMsg = new VehicleExgMsg();
//        vehicleExgMsg.setReportStatus(0);
//        vehicleExgMsg.setRespTime(new Date());
//        vehicleExgMsg.setRespResult(result);
//        vehicleExgMsgService.updateByVehicleNo(vehicleExgMsg);

        return null;
    }

    /**
     * 申请交换指定车辆定位信息应答的下级平台应答
     * todo 下级平台是否需要记录申请结果？？
     *
     * @param msgBodyBytes
     * @return 无需应答
     */
    private PackageData downExgMsgApplyForMonitorStartupAck(byte[] msgBodyBytes) {
        DownExgMsgApplyForMonitorStartupAck downExgMsgApplyForMonitorStartupAck
                = jt809Decode.downExgMsgApplyForMonitorStartupAck(msgBodyBytes);
        int resultCode = downExgMsgApplyForMonitorStartupAck.getResult();
        String result = VehicleExgMsgConstants.applyForMonitorStartup(resultCode);
        log.info("申请交换指定车辆定位信息结果：{}", result);

        // todo 申请交换指定车辆信息上级平台响应后，更新库中的申请记录
//        VehicleExgMsg vehicleExgMsg = new VehicleExgMsg();
//        vehicleExgMsg.setReportStatus(0);
//        vehicleExgMsg.setRespTime(new Date());
//        vehicleExgMsg.setRespResult(result);
//        vehicleExgMsgService.updateByVehicleNo(vehicleExgMsg);

        return null;
    }

    /**
     * 取消车辆定位信息交换请求应答
     * todo 下级平台是否需要记录请求原因？？
     *
     * @param msgBodyBytes
     * @return
     */
    private PackageData downExgMsgReturnEndAck(byte[] msgBodyBytes) {
        byte[] response;
        DownExgMsgReturnEnd downExgMsgReturnEnd = jt809Decode.downExgMsgReturnEnd(msgBodyBytes);
        int reasonCode = downExgMsgReturnEnd.getReasonCode();
        String reason = "";
        if (reasonCode == 0) {
            reason = "车辆离开指定区域";
        } else if (reasonCode == 1) {
            reason = "人工停止交换";
        } else if (reasonCode == 2) {
            reason = "紧急监控完成";
        } else if (reasonCode == 3) {
            reason = "车辆离线";
        } else if (reasonCode == 4) {
            reason = "其他原因";
        }
        log.info("上级平台取消车辆定位信息交换原因：{}", reason);
        UpExgMsgReturnEndAck upExgMsgReturnEndAck = new UpExgMsgReturnEndAck();
        upExgMsgReturnEndAck.setBasicVehicleInfo(downExgMsgReturnEnd.getBasicVehicleInfo());
        response = jt809Encode.upExgMsgReturnEndAck(upExgMsgReturnEndAck);
        return new PackageData(Jt809MsgIdConfig.UP_EXG_MSG_RETURN_END_ACK, response, LinkType.MASTER);
    }

    /**
     * 启动车辆定位信息交换请求应答
     * todo 下级平台是否需要记录请求原因？？
     *
     * @param msgBodyBytes
     * @return
     */
    private PackageData downExgMsgReturnStartupAck(byte[] msgBodyBytes) {
        byte[] response;
        DownExgMsgReturnStartup downExgMsgReturnStartup = jt809Decode.downExgMsgReturnStartup(msgBodyBytes);
        int reasonCode = downExgMsgReturnStartup.getReasonCode();
        String reason = "";
        if (reasonCode == 0) {
            reason = "车辆进入指定区域";
        } else if (reasonCode == 1) {
            reason = "人工指定交换";
        } else if (reasonCode == 2) {
            reason = "应急状态下车辆定位信息回传";
        } else if (reasonCode == 3) {
            reason = "其他原因";
        }
        log.info("上级平台启动车辆定位信息交换的原因：{}", reason);
        UpExgMsgReturnStartupAck upExgMsgReturnStartupAck = new UpExgMsgReturnStartupAck();
        upExgMsgReturnStartupAck.setBasicVehicleInfo(downExgMsgReturnStartup.getBasicVehicleInfo());
        response = jt809Encode.upExgMsgReturnStartupAck(upExgMsgReturnStartupAck);
        return new PackageData(Jt809MsgIdConfig.UP_EXG_MSG_RETURN_STARTUP_ACK, response, LinkType.MASTER);
    }

    /**
     * 车辆动态信息交换应答----end
     */


    //=============================1078音视频================================
    public List<Integer> getAllChannelIds(String vehicleNo){
        //默认有1~4个通道
        List<Integer> channels = new ArrayList<Integer>(){{
            add(1);
            add(2);
            add(3);
            add(4);
        }};
        return channels;
    }

    /**
     * 远程录像回放控制
     *
     * @param body
     * @return
     */
    public PackageData downPlayBackMsgControl(byte[] body) {
        //1、解析
        DownPlayBackMsgControl entity = jt809Decode.downPlayBackMsgControl(body);
        log.info("远程录像回放控制消息!!! {}", entity.toString());
        //2、下发
        String devNo = getDevNoByVehNo(entity.getBasicVehicleInfo());
        log.info("远程录像回放控制消息下发！！！{}", entity.getBasicVehicleInfo().getVehicleNo());
        downPlayBackMsgControlOrder(devNo, entity);
        //3、应答
        UpPlayBackMsgControlAck rsp = new UpPlayBackMsgControlAck();
        rsp.setBasicVehicleInfo(entity.getBasicVehicleInfo());
        rsp.setResult(0);
        return new PackageData(Jt809MsgIdConfig.UP_PLAYBACK_MSG, jt809Encode.upPlayBackMsgControlAck(rsp), LinkType.MASTER);
    }
    //下发指令
    private void downPlayBackMsgControlOrder(String devNo, DownPlayBackMsgControl entity){
        DownPlayBackMsgStartup startup = MediaPlayBackHandle.inst.get(devNo);
        //默认关闭所有通道
        if(startup != null && startup.getChannelId() != 0){
            downPlayBackMsgControlOrder(devNo, startup.getChannelId(), entity);
            return;
        }
        List<Integer> channels = getAllChannelIds(devNo);
        for(Integer channel:channels){
            downPlayBackMsgControlOrder(devNo,  channel, entity);
        }
    }

    private StatusResult downPlayBackMsgControlOrder(String devNo, int channelId, DownPlayBackMsgControl entity){
        HisMediaUploadCmd send = new HisMediaUploadCmd();
        send.setChanelId(channelId);
        send.setPlayControl(entity.getControlType());
        send.setPlaySpeed(entity.getFastType());
        send.setPlayStartTime(entity.getDateTime());
        send.devNo = devNo;
        send.setDistributeMsgTopic(Jt808DistributeMsgTopic.HisMediaUploadCmd_Send);
        StatusResult clientRsp = HttpRequest.postOrder(jt809Config.getHttpRequestUrl(), send, TIMEOUT);
        log.info("远程录像回放控制指令下发！{},channel:{},playControl:{},PlaySpeed; {}, time：{}"
                ,devNo, send.getChanelId(), send.getPlayControl(),send.getPlaySpeed(), send.getPlayStartTime().toString());
        return clientRsp;
    }

    /**
     * 远程录像回放请求消息
     * @return
     * @throws Exception
     */
    public PackageData downPlayBackMsgStartup(byte[] body){
        //1、解析
        DownPlayBackMsgStartup entity = jt809Decode.downPlayBackMsgStartup(body);
        log.info("远程录像回放请求消息!!! {}", entity.toString());
        String devNo = getDevNoByVehNo(entity.getBasicVehicleInfo());
        downPlayBackMsgStartupOrder(devNo, entity);
        MediaPlayBackHandle.inst.add(devNo, entity);
        UpPlayBackMsgStartupAck rsp = getUpPlayBackMsgStartupAck(entity);
        return new PackageData(Jt809MsgIdConfig.UP_PLAYBACK_MSG, jt809Encode.upPlayBackMsgStartupAck(rsp), LinkType.MASTER);
    }

    private UpPlayBackMsgStartupAck getUpPlayBackMsgStartupAck(DownPlayBackMsgStartup entity){
        UpPlayBackMsgStartupAck rsp = new UpPlayBackMsgStartupAck();
        rsp.setBasicVehicleInfo(entity.getBasicVehicleInfo());
        rsp.setServerIp(jt809Config.getVideoServerIp());
        rsp.setServerPort(jt809Config.getVideoHttpServerPort());
        rsp.setResult(0);
        log.info("远程录像回放请求应答!!{},result:{},视频服务地址:{}:{}", rsp.getBasicVehicleInfo().getVehicleNo(),
                rsp.getResult(), rsp.getServerIp(), rsp.getServerPort());
        return rsp;
    }
    //下发指令
    private void downPlayBackMsgStartupOrder(String devNo, DownPlayBackMsgStartup entity){
        if(entity.getChannelId() != 0){
            downPlayBackMsgStartupOrder(devNo, entity.getChannelId(), entity);
            return;
        }
        List<Integer> channels = getAllChannelIds(devNo);
        for(Integer channel:channels){
            downPlayBackMsgStartupOrder(devNo,  channel, entity);
        }
    }

    private void downPlayBackMsgStartupOrder(String devNo, int channelId,  DownPlayBackMsgStartup entity){
        HisMediaUploadReq send = new HisMediaUploadReq();
        send.setIp(jt809Config.getVideoServerIp());
        send.setTcpPort(jt809Config.getVideoTcpServerPort());
        send.setUdpPort(0);
        send.setChanelId(channelId);
        send.setMediaType(entity.getMediaType());
        send.setCodeType(1);
        send.setStorageType(entity.storageType);
        send.setPlayType(0);
        send.setPlaySpeed(0);
        send.setBeginTime(entity.startTime);
        send.setEndTime(entity.endTime);
        send.devNo = devNo;
        send.setDistributeMsgTopic(Jt808DistributeMsgTopic.HisMediaUploadReq_Send);
        StatusResult clientRsp = HttpRequest.postOrder(jt809Config.getHttpRequestUrl(), send, TIMEOUT);
        log.info("远程录像回放请求指令下发！{},channel:{},mediaType:{}, {}:{}, [{}]~[{}]"
                ,devNo, send.getChanelId(), send.getMediaType(),send.getIp(),send.getTcpPort(),
                send.getBeginTime().toString(), send.getEndTime().toString());
    }

    /**
     * 主动请求停止实时音视频传输
     * @return
     * @throws Exception
     */
    public PackageData downRealVideoMsgEnd(byte[] body) {
        DownRealVideoMsgEnd entity = jt809Decode.downRealVideoMsgEnd(body);
        log.info("主动请求停止实时音视频传输消息!!{}", entity.toString());
        String devNo = getDevNoByVehNo(entity.getBasicVehicleInfo());
        downRealVideoMsgEndOrder(devNo, entity);
        UpRealVideoMsgEndAck rsp = getUpRealVideoMsgEndAck(entity);
        return new PackageData(Jt809MsgIdConfig.UP_REALVIDEO_MSG, jt809Encode.upRealVideoMsgEndAck(rsp), LinkType.MASTER);
    }

    private UpRealVideoMsgEndAck getUpRealVideoMsgEndAck(DownRealVideoMsgEnd entity){
        UpRealVideoMsgEndAck rsp = new UpRealVideoMsgEndAck();
        rsp.setBasicVehicleInfo(entity.getBasicVehicleInfo());
        //默认为成功
        rsp.setResult(0);
        log.info("请求停止实时音视频请求应答!! {}", entity.getBasicVehicleInfo().getVehicleNo());
        return rsp;
    }
    //下发指令
    private void downRealVideoMsgEndOrder(String devNo, DownRealVideoMsgEnd entity){
        if(entity.getChannelId() != 0){
            sendUpRealVideoMsgEndOrder(devNo, entity.getChannelId(), entity.getMediaType());
            return;
        }
        List<Integer> channels = getAllChannelIds(devNo);
        for(Integer channel:channels){
            sendUpRealVideoMsgEndOrder(devNo,  channel, entity.getMediaType());
        }
    }

    private void sendUpRealVideoMsgEndOrder(String devNo, int channelId, int mediaType){
        RealtimeMediaUploadCmd send = new RealtimeMediaUploadCmd();
        send.setChanelId(channelId);
        send.setCmdType(0);
        send.setCloseMediaType(mediaType);
        send.setChangeCodeType(0);
        send.devNo = devNo;
        send.setDistributeMsgTopic(Jt808DistributeMsgTopic.RealtimeMediaUploadCmd_Send);
        StatusResult clientRsp = HttpRequest.postOrder(jt809Config.getHttpRequestUrl(), send, TIMEOUT);
        log.info("停止实时音视频传输指令下发！{}, channel:{}"
                ,devNo, send.getChanelId());
    }

    public PackageData downRealVideoMsgStartup(byte[] body){
        DownRealVideoMsgStartup entity = jt809Decode.downRealVideoMsgStartup(body);
        log.info("实时音视频请求消息!!{}", entity.toString());
        //下发
        String devNo = getDevNoByVehNo(entity.getBasicVehicleInfo());
        downRealVideoMsgStartupOrder(devNo, entity);
        UpRealVideoMsgStartupAck rsp = getUpRealVideoMsgStartupAck(entity);
        return new PackageData(Jt809MsgIdConfig.UP_REALVIDEO_MSG, jt809Encode.upRealVideoMsgStartupAck(rsp), LinkType.MASTER);
    }

    private UpRealVideoMsgStartupAck getUpRealVideoMsgStartupAck(DownRealVideoMsgStartup entity){
        UpRealVideoMsgStartupAck rsp = new UpRealVideoMsgStartupAck();
        rsp.setBasicVehicleInfo(entity.getBasicVehicleInfo());
        boolean codeEqual = AuthorizeCode.equal(entity.getAuthorizeCode());
        int result = codeEqual ? 0 : 4;
        //默认为成功
        rsp.setResult(result);
        rsp.setServerIp(jt809Config.getVideoServerIp());
        rsp.setServerPort(jt809Config.getVideoHttpServerPort());
        log.info("实时音视频请求消息应答!!{},result:{},视频服务地址:{}:{}", rsp.getBasicVehicleInfo().getVehicleNo(),
                rsp.getResult(), rsp.getServerIp(), rsp.getServerPort());
        return rsp;
    }
    //下发指令
    private void downRealVideoMsgStartupOrder(String devNo, DownRealVideoMsgStartup entity){
        if(entity.getChannelId() != 0){
            downRealVideoMsgStartupOrder(devNo, entity.getMediaType(),entity.getChannelId());
            return;
        }
        List<Integer> channels = getAllChannelIds(devNo);
        for(Integer channel:channels){
            downRealVideoMsgStartupOrder(devNo, entity.getMediaType(),channel);
        }
    }

    private void downRealVideoMsgStartupOrder(String devNo, int mediaType, int channel){
        RealtimeMediaUploadReq send = new RealtimeMediaUploadReq();
        send.setDistributeMsgTopic(Jt808DistributeMsgTopic.RealtimeMediaUploadReq_Send);
        send.setIp(jt809Config.getVideoServerIp());
        send.setTcpPort(jt809Config.getVideoTcpServerPort());
        send.setUdpPort(0);
        send.setChanelId(channel);
        send.setMediaType(mediaType);
        send.setCodeType(1);
        send.devNo = devNo;
        send.setDistributeMsgTopic(Jt808DistributeMsgTopic.RealtimeMediaUploadReq_Send);
        StatusResult clientRsp = HttpRequest.postOrder(jt809Config.getHttpRequestUrl(), send, TIMEOUT);
        log.info("实时音视频请求指令下发！{}:{},channel:{},mediaType:{}"
                ,send.getIp(),send.getTcpPort(),send.getChanelId(),send.getMediaType());
    }

    /**
     * 主动上传音视频资源目录信息应答消息
     * @return
     */
    public PackageData downFileListMsgAck(byte[] body) {
        DownFileListMsgAck entity = jt809Decode.downFileListMsgAck(body);
        log.info("主动上传音视频资源目录信息应答消息！！！{},应答结果:{},资源目录总数{}"
                ,entity.getBasicVehicleInfo().getVehicleNo(),
                entity.getResult(), entity.getCount());
        return null;
    }

    /**
     * 查询音视频资源目录请求消息
     * @return
     * @throws Exception
     */
    public PackageData downRealVideoFileListReq(byte[] body){
        DownRealVideoFileListReq entity = jt809Decode.downRealVideoFileListReq(body);
        String devNo = getDevNoByVehNo(entity.getBasicVehicleInfo());
        MediaListHandle.inst.add(devNo, entity);
        log.info("查询音视频资源目录请求消息！！！{},{}", devNo, entity.toString());
        downRealVideoFileListReqOrder(devNo, entity);
        return null;
    }

    private void downRealVideoFileListReqOrder(String devNo, DownRealVideoFileListReq entity){
        QueryMediaList send = new QueryMediaList();
        send.setChanelId(entity.getChannelId());
        send.setBeginTime(entity.startTime);
        send.setEndTime(entity.endTime);
        send.setGpsAlarmFlag(entity.getGpsAlarmFlag());
        send.setMediaAlarmFlag(entity.getMediaAlarmFlag());
        send.setMediaType(entity.mediaType);
        send.setCodeType(1);
        send.setStorageType(entity.storageType);
        send.devNo = devNo;
        send.setDistributeMsgTopic(Jt808DistributeMsgTopic.QueryMediaList_Send);
        StatusResult clientRsp = HttpRequest.postOrder(jt809Config.getHttpRequestUrl(), send, TIMEOUT);
        log.info("查询音视频资源目录请求指令下发！{},channel:{},mediaType:{},mediaAlarm:{},gpsAlarm:{}," +
                        "[{}]~[{}]"
                ,devNo, send.getChanelId(), send.getMediaType(), send.getMediaAlarmFlag(), send.getGpsAlarmFlag(),
                send.getBeginTime().toString(), send.getEndTime().toString());
    }
}
